package warehouse

import (
	"context"
	"errors"
	"fmt"
	"github.com/google/wire"
	"go.manyji.com/lib/log"
	"sieve_admin_server/app/dao"
	"sieve_admin_server/app/dao/warehouse"
	"sieve_admin_server/app/schema"
	serviceCustomer "sieve_admin_server/app/service/customer"
	serviceLog "sieve_admin_server/app/service/logger"
	pkgTime "sieve_admin_server/pkg/time"
	"sieve_admin_server/pkg/util"
	"strconv"
	"time"
)

var (
	WarehouseSet = wire.NewSet(wire.Struct(new(WarehouseSrv), "*"))
)

type WarehouseSrv struct {
	UserSrv       *serviceCustomer.UserSrv
	BusinessSrv   *serviceLog.BusinessSrv
	WarehouseRepo *dao.WarehouseRepo
}

func (a *WarehouseSrv) GetByName(ctx context.Context, uid uint64, name string) (*warehouse.Warehouse, error) {

	var (
		tableName = warehouse.Warehouse{}
		querySQL  = fmt.Sprintf(`
	SELECT * FROM %v 
	WHERE name = '%v' AND creator = %v
	AND deleted = 0
`, tableName.TableName(), name, uid)
	)

	req, err := a.WarehouseRepo.QueryRaw(ctx, querySQL, warehouse.Warehouse{})
	if err != nil {
		return nil, err
	}

	if req == nil {
		return nil, errors.New(fmt.Sprintf("record not  found"))
	}

	return req[0].(*warehouse.Warehouse), nil
}

func (a *WarehouseSrv) requestCheck(ctx context.Context, item map[string]interface{}) error {

	if _, ok := item["name"]; !ok {
		return errors.New("参数错误")
	}

	if _, ok := item["type"]; !ok {
		return errors.New("参数错误")
	}

	return nil
}

func (a *WarehouseSrv) Create(ctx context.Context, userId uint64, item map[string]interface{}) error {

	if err := a.requestCheck(ctx, item); err != nil {
		return err
	}

	var (
		now = time.Now().Unix()
		def = map[string]interface{}{
			"creator":    userId,
			"create_at":  now,
			"updated_at": now,
		}
	)

	for k, v := range def {
		item[k] = v
	}

	var (
		logType = "业务日志"
		logName = "创建仓库"
		logMsg  string
	)

	defer func() {
		go func() {
			if req := a.BusinessSrv.CreateBusinessRecord(context.Background(), userId, logType, logName, logMsg); req != nil {
				log.Info(fmt.Sprintf("%+v", req))
			}
		}()
	}()

	if respWarehouse, err := a.GetByName(ctx, userId, item["name"].(string)); err == nil && respWarehouse != nil {
		logType = "异常日志"
		logMsg = "仓库名已存在"
		return errors.New(fmt.Sprintf("仓库名已存在"))
	}

	err := a.WarehouseRepo.Create(ctx, item)
	if err != nil {
		logType = "异常日志"
		logMsg = err.Error()
	}

	return err
}

func (a *WarehouseSrv) Delete(ctx context.Context, reqArgs map[string]interface{}) error {

	var (
		id, _ = strconv.ParseUint(fmt.Sprintf("%v", reqArgs["id"]), 10, 64)
	)

	return a.WarehouseRepo.SoftDelete(ctx, id)
}

func (a *WarehouseSrv) Query(ctx context.Context, uid uint64, reqArgs map[string]interface{}, p schema.PaginationParam) interface{} {

	var (
		err         error
		logMsg      string
		isAdminRole bool
	)
	_, err = a.UserSrv.GetUserInfo(ctx, uid, &isAdminRole)
	if err != nil {
		logMsg = err.Error()
		return err
	}
	if _, ok := reqArgs["name"]; ok {
		ctx = context.WithValue(ctx,
			"condition", map[string]string{"name": "LIKE"},
		)

		reqArgs["name"] = "'%" + reqArgs["name"].(string) + "%'"
	}

	var (
		entity  = warehouse.Warehouse{}
		logType = "业务日志"
		logName = fmt.Sprintf("查询仓库")

		repKeys = util.Struct2Slice(entity, "json", entity.TableName())
	)

	defer func() {
		if err == nil {
			go func() {

				return

				log.Info(fmt.Sprintf("查询仓库 %+v",
					a.BusinessSrv.CreateBusinessRecord(context.Background(), uid, logType, logName, logMsg)))
			}()
		}
	}()

	// 管理员账号不需要额外的连表查询
	if !isAdminRole {
		//var (
		//	joinString = fmt.Sprintf(
		//		"INNER JOIN user ON "+
		//			"(warehouse.creator = user.id AND warehouse.creator = %v)"+
		//			" OR (warehouse.creator = user.leader_id AND warehouse.creator = %v)"+
		//			" OR (warehouse.creator = user.top_leader_id  AND warehouse.creator = %v)", uid, uid, uid)
		//)

		var (
			joinString = fmt.Sprintf(
				"INNER JOIN user ON "+
					"warehouse.creator = user.id AND (user.id = %v"+
					" OR user.leader_id = %v "+
					" OR user.top_leader_id = %v)", uid, uid, uid)
		)

		ctx = context.WithValue(
			context.WithValue(ctx, "join", joinString),
			"group_by", "warehouse.id")
	}

	req, err := a.WarehouseRepo.Query(ctx, reqArgs, p, repKeys)
	if err != nil {
		return err
	}
	return req
}

func (a *WarehouseSrv) CreateTask(ctx context.Context, item map[string]interface{}) error {

	var (
		now = time.Now().Unix()
		def = map[string]interface{}{
			"create_at":  now,
			"updated_at": now,
		}
	)

	for k, v := range def {
		item[k] = v
	}

	return a.WarehouseRepo.Create(ctx, item)
}

// 获取仓库过期时间描述
func (a *WarehouseSrv) GetExpiredTime(ctx context.Context, item map[string]interface{}) interface{} {

	var (
		expired string
		period  = 3
	)

	if _, ok := item["id"]; !ok {
		return map[string]interface{}{
			"period": period,
		}
	}

	var (
		p = schema.PaginationParam{
			OnlyData: true,
		}
		reqArgs = map[string]interface{}{
			"id": item["id"],
		}
		repKeys = []string{"create_at"}
	)
	req, err := a.WarehouseRepo.Query(context.Background(), reqArgs, p, repKeys)
	if err != nil {
		return ""
	}

	for _, v := range req.(map[string]interface{})["list"].([]interface{}) {

		vv := v.(*warehouse.Warehouse).CreateAt
		expired = pkgTime.Format(time.Unix(vv, 0).AddDate(0, 3, 0).Unix())
	}

	return map[string]interface{}{
		"expired": expired,
		"period":  period,
	}
}

func (a *WarehouseSrv) GetBitArray(ctx context.Context, warehouseId int64, ty int, args ...interface{}) (string, error) {

	var (
		p = schema.PaginationParam{
			OnlyData: true,
		}
		reqArgs = map[string]interface{}{
			"warehouse_id": warehouseId,
			"type":         ty,
		}
		repKeys       = []string{"sieve_open_bitarray", "sieve_active_bitarray", "sieve_sex_bitarray"}
		outBitArrayTy int
		m             = map[int]string{
			1: "sieve_open_bitarray",
			2: "sieve_active_bitarray",
			3: "sieve_sex_bitarray",
		}
	)

	if len(args) == 1 {
		outBitArrayTy = args[0].(int)
	}

	if len(args) == 2 {
		outBitArrayTy = args[0].(int)
		reqArgs["country"] = args[1].(int64)
	}

	ret, err := a.WarehouseRepo.Query(context.Background(), reqArgs, p, repKeys)
	if err != nil {
		return "", err
	}

	v := ret.(map[string]interface{})["list"].(map[string]interface{})[m[outBitArrayTy]].(string)

	return v, nil
}
